package cn.sc.summer.mybatis.config.datasource;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.sc.summer.mybatis.properties.DruidConfigProperties;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.util.Utils;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.baomidou.mybatisplus.annotation.DbType;
import cn.sc.summer.constant.project.ProjectConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.*;
import java.io.IOException;
import java.util.Arrays;

/**
 * 类名：德鲁伊监控配置
 *
 * @author a-xin
 * @date 2023/9/30 13:23
 */
@Slf4j
@Configuration
@EnableConfigurationProperties({DruidStatProperties.class, DruidConfigProperties.class})
public class DruidConfig {

    static {
        System.setProperty("druid.mysql.usePingMethod", "false");
    }

    @Bean
    public ServletRegistrationBean<StatViewServlet> registrationBean(DruidConfigProperties druidConfigProperties) {
        log.info("==> Start initializing the druid connection pool...");
        ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        // 添加IP白名单
        if (CollUtil.isNotEmpty(Arrays.asList(druidConfigProperties.getWhitelist()))) {
            servletRegistrationBean.addInitParameter("allow", String.join(",", Arrays.asList(druidConfigProperties.getWhitelist())));
        }
        // 添加IP黑名单，当白名单和黑名单重复时，黑名单优先级更高
        if (CollUtil.isNotEmpty(Arrays.asList(druidConfigProperties.getBlacklist()))) {
            servletRegistrationBean.addInitParameter("deny", String.join(",", Arrays.asList(druidConfigProperties.getBlacklist())));
        }

        // 添加控制台管理用户
        String loginUser = StrUtil.isBlank(druidConfigProperties.getUserName()) ? "root" : druidConfigProperties.getUserName();
        String password = StrUtil.isBlank(druidConfigProperties.getPassWord()) ? "root" : druidConfigProperties.getPassWord();

        servletRegistrationBean.addInitParameter("loginUsername", loginUser);
        servletRegistrationBean.addInitParameter("loginPassword", password);
        // 是否能够重置数据
        servletRegistrationBean.addInitParameter("resetEnable", "false");

        log.info("\n	-------------------------------------------------------------\n\t" +
                "Druid Web is complete: [" + ProjectConstant.SERVER_NAME + "] ->【 login: " + loginUser + ", " + "password: " + password + " 】\n\t" +
                "-------------------------------------------------------------");
        return servletRegistrationBean;

    }

    /**
     * 配置服务过滤器
     *
     * @return 返回过滤器配置对象
     */
    @Bean
    public FilterRegistrationBean<WebStatFilter> statFilter() {
        FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(new WebStatFilter());
        // 添加过滤规则
        filterRegistrationBean.addUrlPatterns("/*");
        // 忽略过滤格式
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,");
        return filterRegistrationBean;
    }

    /**
     * 除去页面底部的广告
     *
     * @param properties druid噢诶之参数
     * @return org.springframework.boot.web.servlet.FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean<Filter> removeDruidAdFilterRegistrationBean(DruidStatProperties properties) {
        // 获取web监控页面的参数
        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
        // 提取common.js的配置路径
        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
        String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");

        final String filePath = "support/http/resources/js/common.js";

        //创建filter进行过滤
        Filter filter = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) {
            }

            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                chain.doFilter(request, response);
                // 重置缓冲区，响应头不会被重置
                response.resetBuffer();
                // 获取common.js
                String text = Utils.readFromResource(filePath);
                // 正则替换banner, 除去底部的广告信息
                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
                text = text.replaceAll("powered.*?shrek.wang</a>", "");
                response.getWriter().write(text);
            }

            @Override
            public void destroy() {
                Filter.super.destroy();
            }
        };
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns(commonJsPattern);
        return registrationBean;
    }

    @Bean
    public WallFilter wallFilter() {
        WallConfig config = new WallConfig();
        //允许一次执行多条语句
        config.setMultiStatementAllow(true);
        //允许非基本语句的其他语句
        config.setNoneBaseStatementAllow(true);
        WallFilter wallFilter = new WallFilter();
        wallFilter.setDbType(DbType.MYSQL.getDb());
        wallFilter.setConfig(config);
        wallFilter.setThrowException(Boolean.FALSE);
        wallFilter.setLogViolation(Boolean.TRUE);
        return wallFilter;
    }

}


